/*
* Chrysalix
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
* See the AUTHORS.txt file in the distribution for a full listing of
* individual contributors.
*
* Chrysalix is free software. Unless otherwise indicated, all code in Chrysalix
* is licensed to you under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Chrysalix is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.modelspace.internal;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Calendar;
import java.util.concurrent.ExecutionException;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.modelspace.Metamodel;
import org.modelspace.MetamodelManager;
import org.modelspace.Model;
import org.modelspace.Modelspace;
import org.modelspace.ModelspaceException;
import org.modelspace.ModelspaceI18n;
import org.modelspace.ModelspaceLexicon;
import org.modelspace.internal.task.SystemTask;
import org.modelspace.internal.task.SystemTaskWithResult;
import org.modelspace.internal.task.Task;
import org.modelspace.internal.task.TaskWithResult;
import org.modelspace.internal.task.WriteSystemTask;
import org.modelspace.internal.task.WriteTask;
import org.modelspace.internal.task.WriteTaskWithResult;
import org.modelspace.spi.DependencyProcessor;
import org.modelspace.spi.Exporter;
import org.modeshape.common.collection.Problem;
import org.modeshape.common.collection.Problems;
import org.modeshape.common.util.CheckArg;
import org.modeshape.jcr.JcrLexicon;
import org.modeshape.jcr.JcrRepository;
import org.modeshape.jcr.ModeShapeEngine;
import org.modeshape.jcr.NoSuchRepositoryException;
import org.modeshape.jcr.RepositoryConfiguration;
import org.modeshape.jcr.api.JcrTools;
import org.modeshape.jcr.api.ValueFactory;
import org.modeshape.jcr.api.sequencer.Sequencer;
/**
*
*/
public class ModelspaceImpl implements Modelspace {
private static final String EXISTING_MODEL_HAS_WRONG_METAMODEL_TYPE =
"Existing model at '%s' did not have metamodel type of '%s.";
private static final String NOT_MODEL_PATH = "Not a path to a model: %s";
/**
* The path to the default configuration, which uses a file-based repository
*/
public static final String DEFAULT_CONFIGURATION_PATH = "config.json";
/**
*
*/
public static final String REPOSITORY_STORE_PARENT_PATH_PROPERTY = "org.modelspace.repositoryStoreParentPath";
private ModeShapeEngine engine;
private JcrRepository repository;
private MetamodelManagerImpl metamodelManager;
private final String configurationPath;
/**
* Uses a default configuration.
*
* @param repositoryStoreParentPath
* the path to the folder that should contain the repository store
*/
public ModelspaceImpl( final String repositoryStoreParentPath ) {
this( repositoryStoreParentPath, DEFAULT_CONFIGURATION_PATH );
}
/**
* @param repositoryStoreParentPath
* the path to the folder that should contain the repository store
* @param configurationPath
* the path to a configuration file
*/
public ModelspaceImpl( final String repositoryStoreParentPath,
final String configurationPath ) {
CheckArg.isNotEmpty( repositoryStoreParentPath, "repositoryStoreParentPath" );
CheckArg.isNotEmpty( configurationPath, "configurationPath" );
System.setProperty( REPOSITORY_STORE_PARENT_PATH_PROPERTY, repositoryStoreParentPath );
this.configurationPath = configurationPath;
}
String absolutePath( String path ) {
if ( path == null ) return "/";
path = path.trim();
if ( path.isEmpty() ) return "/";
if ( path.charAt( 0 ) == '/' ) return path;
return '/' + path;
}
private String absolutePath( String path,
final String name ) {
path = absolutePath( path );
return path.endsWith( "/" ) ? path + name : path + '/' + name;
}
/**
* {@inheritDoc}
*
* @see AutoCloseable#close()
*/
@Override
public void close() throws ModelspaceException {
try {
if ( engine != null ) engine.shutdown().get();
} catch ( InterruptedException | ExecutionException e ) {
throw new ModelspaceException( e, "Unable to shutdown modelspace engine" );
}
Modelspace.LOGGER.info( "Modelspace stopped" );
}
/**
* {@inheritDoc}
*
* @see Modelspace#configurationPath()
*/
@Override
public String configurationPath() {
return configurationPath;
}
Node dataNode( final Session session,
final String filePath ) throws Exception {
try {
return session.getNode( filePath.charAt( 0 ) == '/' ? filePath : '/' + filePath );
} catch ( final PathNotFoundException e ) {
throw new IllegalArgumentException( e );
}
}
/**
* {@inheritDoc}
*
* @see org.modelspace.Modelspace#deleteModel(java.lang.String)
*/
@Override
public boolean deleteModel( final String path ) throws ModelspaceException {
return run( new WriteTaskWithResult< Boolean >() {
/**
* {@inheritDoc}
*
* @see org.modelspace.internal.task.WriteTaskWithResult#run(javax.jcr.Session)
*/
@Override
public Boolean run( final Session session ) throws Exception {
final String absPath = absolutePath( path );
if ( session.nodeExists( absPath ) ) {
final Node node = session.getNode( absPath );
if ( !node.isNodeType( ModelspaceLexicon.Model.MODEL_MIXIN ) ) {
throw new IllegalArgumentException( ModelspaceI18n.localize( NOT_MODEL_PATH, absPath ) );
}
return true;
}
return false;
}
} );
}
/**
* {@inheritDoc}
*
* @see Modelspace#export(Model, File)
*/
@Override
public void export( final Model model,
final File file ) throws ModelspaceException {
CheckArg.isNotNull( model, "model" );
CheckArg.isNotNull( file, "file" );
try {
export( model, new FileOutputStream( file ) );
} catch ( final FileNotFoundException e ) {
throw new ModelspaceException( e, "Unable to export \"%s\" to \"%s\"", model, file );
}
}
/**
* {@inheritDoc}
*
* @see Modelspace#export(Model, OutputStream)
*/
@Override
public void export( final Model model,
final OutputStream stream ) throws ModelspaceException {
CheckArg.isNotNull( model, "model" );
CheckArg.isNotNull( stream, "stream" );
final Metamodel metamodel = model.metamodel();
if ( metamodel != null ) {
final Exporter exporter = metamodel.exporter();
if ( exporter != null ) {
exporter.execute( model, stream );
}
}
throw new ModelspaceException( "Model '%s' cannot be exported since an exporter was not found", model.name() );
}
/**
* {@inheritDoc}
*
* @see Modelspace#export(Model, URL)
*/
@Override
public void export( final Model model,
final URL url ) throws ModelspaceException {
CheckArg.isNotNull( model, "model" );
CheckArg.isNotNull( url, "url" );
try ( OutputStream stream = url.openConnection().getOutputStream() ) {
export( model, stream );
} catch ( final IOException e ) {
throw new ModelspaceException( e, "Unable to export \"%s\" to \"%s\"", model, url );
}
}
/**
* {@inheritDoc}
*
* @see Modelspace#generateModel(String, String)
*/
@Override
public Model generateModel( final String dataPath,
final String modelPath ) throws ModelspaceException {
return generateModel( dataPath, modelPath, null, true );
}
/**
* {@inheritDoc}
*
* @see Modelspace#generateModel(String, String, Metamodel)
*/
@Override
public Model generateModel( final String dataPath,
final String modelPath,
final Metamodel metamodel ) throws ModelspaceException {
return generateModel( dataPath, modelPath, metamodel, true );
}
/**
* @param dataPath
* the workspace path to the data
* @param modelPath
* the workspace path to the model
* @param metamodel
* the model's metamodel
* @param persistArtifact
* <code>true</code> if the data should be persisted after import
* @return the model
* @throws ModelspaceException
* if an error occurs
*/
public Model generateModel( final String dataPath,
final String modelPath,
final Metamodel metamodel,
final boolean persistArtifact ) throws ModelspaceException {
CheckArg.isNotEmpty( dataPath, "dataPath" );
CheckArg.isNotEmpty( modelPath, "modelPath" );
try {
return run( new WriteTaskWithResult< Model >() {
@Override
public Model run( final Session session ) throws Exception {
final Node dataNode = dataNode( session, dataPath );
Metamodel actualMetamodel = metamodel;
if ( actualMetamodel == null ) {
// If no metamodel supplied, use default metamodel if one exists
final MetamodelManagerImpl manager = ( MetamodelManagerImpl ) metamodelManager();
actualMetamodel = manager.defaultMetamodel( dataNode, manager.metamodels( dataNode ) );
if ( actualMetamodel == null )
throw new IllegalArgumentException( ModelspaceI18n.localize( "Unable to determine default metamodel for file %s",
dataPath ) );
throw new UnsupportedOperationException( "Not yet implemented" );
}
// Build the model
final ValueFactory valueFactory = ( ValueFactory ) session.getValueFactory();
final Calendar cal = Calendar.getInstance();
final Node modelNode = new JcrTools().findOrCreateNode( session, absolutePath( modelPath ) );
modelNode.addMixin( ModelspaceLexicon.Model.MODEL_MIXIN );
if ( dataNode.hasProperty( ModelspaceLexicon.Model.EXTERNAL_LOCATION ) )
modelNode.setProperty( ModelspaceLexicon.Model.EXTERNAL_LOCATION,
dataNode.getProperty( ModelspaceLexicon.Model.EXTERNAL_LOCATION ).getString() );
final SequencerImporter importer = ( SequencerImporter ) actualMetamodel.importer();
final boolean save = importer.execute( dataNode.getNode( JcrLexicon.CONTENT.getString() )
.getProperty( JcrLexicon.DATA.getString() ),
modelNode,
new Sequencer.Context() {
@Override
public Calendar getTimestamp() {
return cal;
}
@Override
public ValueFactory valueFactory() {
return valueFactory;
}
} );
if ( save ) {
modelNode.setProperty( ModelspaceLexicon.Model.METAMODEL, actualMetamodel.id() );
final ModelImpl model = new ModelImpl( ModelspaceImpl.this, modelNode.getPath() );
session.save();
processDependencies( dataPath, modelNode, model, persistArtifact );
return model;
}
throw new ModelspaceException( "Unable to create %s model \"%s\" from data at \"%s\"",
actualMetamodel.name(), modelPath, dataPath );
}
} );
} finally {
if ( !persistArtifact ) {
removeTemporaryArtifact( dataPath );
}
}
}
/**
* {@inheritDoc}
*
* @see Modelspace#importData(File, String)
*/
@Override
public String importData( final File file,
final String workspaceFolder ) throws ModelspaceException {
return importData( file, workspaceFolder, null );
}
/**
* {@inheritDoc}
*
* @see Modelspace#importData(File, String, String)
*/
@Override
public String importData( final File file,
final String workspaceFolder,
final String workspaceName ) throws ModelspaceException {
CheckArg.isNotNull( file, "file" );
try {
return importData( file.toURI().toURL(), workspaceFolder, workspaceName );
} catch ( final MalformedURLException e ) {
throw new ModelspaceException( e, "Unable to import data from \"%s\" to \"%s/%s\"", file,
workspaceFolder, workspaceName );
}
}
/**
* {@inheritDoc}
*
* @see Modelspace#importData(InputStream, String)
*/
@Override
public String importData( final InputStream stream,
final String workspacePath ) throws ModelspaceException {
CheckArg.isNotNull( stream, "stream" );
CheckArg.isNotEmpty( workspacePath, "workspacePath" );
return run( new WriteTaskWithResult< String >() {
@Override
public String run( final Session session ) throws Exception {
// Ensure the path is non-null, absolute, and ends with a slash
final Node node = new JcrTools().uploadFile( session, absolutePath( workspacePath ), stream );
// Add unstructured mix-in to allow node to contain anything else, like models created later
node.addMixin( ModelspaceLexicon.UNSTRUCTURED_MIXIN );
return node.getPath();
}
} );
}
/**
* {@inheritDoc}
*
* @see Modelspace#importData(URL, String)
*/
@Override
public String importData( final URL url,
final String workspaceFolder ) throws ModelspaceException {
return importData( url, workspaceFolder, null );
}
/**
* {@inheritDoc}
*
* @see Modelspace#importData(URL, String, String)
*/
@Override
public String importData( final URL url,
final String workspaceFolder,
final String workspaceName ) throws ModelspaceException {
CheckArg.isNotNull( url, "url" );
try {
final String path = importData( url.openStream(), absolutePath( workspaceFolder, name( workspaceName, url ) ) );
saveExternalLocation( path, url.toString() );
return path;
} catch ( final FileNotFoundException e ) {
throw new IllegalArgumentException( e );
} catch ( final IOException e ) {
throw new ModelspaceException( e, "Unable to import data from \"%s\" to \"%s/%s\"", url,
workspaceFolder, workspaceName );
}
}
/**
* {@inheritDoc}
*
* @see Modelspace#importModel(File, String, Metamodel)
*/
@Override
public Model importModel( final File file,
final String modelFolder,
final Metamodel metamodel ) throws ModelspaceException {
return importModel( file, modelFolder, null, metamodel );
}
/**
* {@inheritDoc}
*
* @see Modelspace#importModel(File, String, String, Metamodel)
*/
@Override
public Model importModel( final File file,
final String modelFolder,
final String modelName,
final Metamodel metamodel ) throws ModelspaceException {
CheckArg.isNotNull( file, "file" );
try {
return importModel( file.toURI().toURL(), modelFolder, modelName, metamodel );
} catch ( final MalformedURLException e ) {
throw new ModelspaceException( e, "Unable to import model from \"%s\" to \"%s/%s\"", file,
modelFolder, modelName );
}
}
/**
* {@inheritDoc}
*
* @see Modelspace#importModel(InputStream, String, Metamodel)
*/
@Override
public Model importModel( final InputStream stream,
final String modelPath,
final Metamodel metamodel ) throws ModelspaceException {
final String dataPath = importData( stream, ModelspaceLexicon.TEMP_FOLDER + "/file" );
return generateModel( dataPath, modelPath, metamodel, false );
}
/**
* {@inheritDoc}
*
* @see Modelspace#importModel(URL, String, Metamodel)
*/
@Override
public Model importModel( final URL dataUrl,
final String modelFolder,
final Metamodel metamodel ) throws ModelspaceException {
return importModel( dataUrl, modelFolder, null, metamodel );
}
/**
* {@inheritDoc}
*
* @see Modelspace#importModel(URL, String, String, Metamodel)
*/
@Override
public Model importModel( final URL dataUrl,
final String modelFolder,
final String modelName,
final Metamodel metamodel ) throws ModelspaceException {
final String dataPath = importData( dataUrl, ModelspaceLexicon.TEMP_FOLDER );
return generateModel( dataPath, absolutePath( modelFolder, name( modelName, dataUrl ) ), metamodel, false );
}
/**
* {@inheritDoc}
*
* @see Modelspace#metamodelManager()
*/
@Override
public MetamodelManager metamodelManager() throws ModelspaceException {
if ( metamodelManager == null ) metamodelManager = new MetamodelManagerImpl( this );
return metamodelManager;
}
/**
* {@inheritDoc}
*
* @see Modelspace#model(String)
*/
@Override
public Model model( final String path ) throws ModelspaceException {
CheckArg.isNotEmpty( path, "path" );
return run( new TaskWithResult< Model >() {
@Override
public Model run( final Session session ) throws Exception {
try {
final String absPath = absolutePath( path );
final Node node = session.getNode( absPath );
if ( !node.isNodeType( ModelspaceLexicon.Model.MODEL_MIXIN ) )
throw new IllegalArgumentException( ModelspaceI18n.localize( "Not a path to a model: %s", absPath ) );
return new ModelImpl( ModelspaceImpl.this, absPath );
} catch ( final PathNotFoundException e ) {
return null;
}
}
} );
}
private String name( String workspaceName,
final URL url ) {
if ( workspaceName != null && !workspaceName.trim().isEmpty() ) return workspaceName;
workspaceName = url.getPath();
workspaceName = workspaceName.substring( workspaceName.lastIndexOf( '/' ) + 1 );
return workspaceName;
}
/**
* {@inheritDoc}
*
* @see org.modelspace.Modelspace#newModel(java.lang.String, java.lang.String)
*/
@Override
public Model newModel( final String modelPath,
final String metamodelId ) throws ModelspaceException {
return newModel( modelPath, metamodelId, false );
}
/**
* {@inheritDoc}
*
* @see org.modelspace.Modelspace#newModel(java.lang.String, java.lang.String, boolean)
*/
@Override
public Model newModel( final String modelPath,
final String metamodelId,
final boolean override ) throws ModelspaceException {
CheckArg.isNotEmpty( modelPath, "modelPath" );
CheckArg.isNotEmpty( metamodelId, "metamodelId" );
return run( new TaskWithResult< Model >() {
/**
* {@inheritDoc}
*
* @see org.modelspace.internal.task.TaskWithResult#run(javax.jcr.Session)
*/
@Override
public Model run( final Session session ) throws Exception {
boolean create = true;
final String absPath = absolutePath( modelPath );
if ( session.nodeExists( absPath ) ) {
if ( override ) {
// delete
session.getNode( absPath ).remove();
} else {
final Node node = session.getNode( absPath );
// make sure it is a model with the right metamodel ID
if ( !node.isNodeType( ModelspaceLexicon.Model.MODEL_MIXIN )
|| !node.hasProperty( ModelspaceLexicon.Model.METAMODEL )
|| !metamodelId.equals( node.getProperty( ModelspaceLexicon.Model.METAMODEL ).getValue().getString() ) ) {
throw new ModelspaceException( ModelspaceI18n.localize( EXISTING_MODEL_HAS_WRONG_METAMODEL_TYPE,
absPath,
metamodelId ) );
}
create = false;
}
}
if ( create ) {
final Node modelNode = new JcrTools().findOrCreateNode( session, absPath );
modelNode.addMixin( ModelspaceLexicon.Model.MODEL_MIXIN );
modelNode.setProperty( ModelspaceLexicon.Model.METAMODEL, metamodelId );
}
return new ModelImpl( ModelspaceImpl.this, absPath );
}
} );
}
void processDependencies( final String dataPath,
final Node modelNode,
final ModelImpl model,
final boolean persistArtifacts ) throws Exception {
if ( model.metamodel() == null ) {
Modelspace.LOGGER.debug( "No metamodel found for model '%s'", modelNode.getName() );
return;
}
final DependencyProcessor dependencyProcessor = model.metamodel().dependencyProcessor();
if ( dependencyProcessor == null ) {
Modelspace.LOGGER.debug( "No dependency processor found for model '%s'", modelNode.getName() );
} else {
dependencyProcessor.process( dataPath, modelNode, this, persistArtifacts );
}
}
private void removeTemporaryArtifact( final String dataPath ) throws ModelspaceException {
run( new WriteTask() {
@Override
public void run( final Session session ) throws Exception {
session.getNode( dataPath ).remove();
}
} );
}
JcrRepository repository() throws ModelspaceException {
if ( repository == null ) {
try {
engine = new ModeShapeEngine();
engine.start();
final RepositoryConfiguration config = RepositoryConfiguration.read( configurationPath );
final Problems problems = config.validate();
if ( problems.hasProblems() ) {
for ( final Problem problem : problems )
Modelspace.LOGGER.error( problem.getThrowable(), "Invalid repository configuration: %s",
problem.getMessageString() );
throw problems.iterator().next().getThrowable();
}
JcrRepository repository;
try {
repository = engine.getRepository( config.getName() );
} catch ( final NoSuchRepositoryException err ) {
repository = engine.deploy( config );
}
this.repository = repository;
Modelspace.LOGGER.info( "Modelspace started" );
} catch ( final Throwable e ) {
throw new ModelspaceException( e, "Unable to start repository" );
}
}
return repository;
}
/**
* {@inheritDoc}
*
* @see Modelspace#repositoryStoreParentPath()
*/
@Override
public String repositoryStoreParentPath() {
return System.getProperty( REPOSITORY_STORE_PARENT_PATH_PROPERTY );
}
/**
* Runs the supplied task after logging into and starting a session with the underlying repository engine that uses the system
* workspace, then afterwards closes the session. It is the caller's responsibility to save any changes made within the session.
*
* @param systemObject
* the object whose simple class name will be passed as a node to the supplied task
* @param task
* the system task to run
* @throws ModelspaceException
* if any error occurs
*/
public void run( final Object systemObject,
final SystemTask task
) throws ModelspaceException {
try {
final Session session = systemSession();
try {
task.run( session, systemNode( session, systemObject ) );
} catch ( final RuntimeException | ModelspaceException e ) {
throw e;
} catch ( final Exception e ) {
throw new ModelspaceException( e, "Unable to perform system task" );
} finally {
session.logout();
}
} catch ( final RepositoryException e ) {
throw new ModelspaceException( e, "Unable to open session for system task" );
}
}
/**
* Runs the supplied task after logging into and starting a session with the underlying repository engine that uses the system
* workspace, then afterwards closes the session. It is the caller's responsibility to save any changes made within the session.
*
* @param systemObject
* the object whose simple class name will be passed as a node to the supplied task
* @param task
* the system task to run
* @return the return value of the supplied task
* @throws ModelspaceException
* if any error occurs
*/
public < T > T run( final Object systemObject,
final SystemTaskWithResult< T > task
) throws ModelspaceException {
try {
final Session session = systemSession();
try {
return task.run( session, systemNode( session, systemObject ) );
} catch ( final RuntimeException | ModelspaceException e ) {
throw e;
} catch ( final Exception e ) {
throw new ModelspaceException( e, "Unable to perform system task with result" );
} finally {
session.logout();
}
} catch ( final RepositoryException e ) {
throw new ModelspaceException( e, "Unable to open session for system task with result" );
}
}
/**
* Runs the supplied task after logging into and starting a session with the underlying repository engine that uses the system
* workspace, then afterwards saves and closes the session.
*
* @param systemObject
* the object whose simple class name will be passed as a node to the supplied task
* @param task
* the system task to run
* @throws ModelspaceException
* if any error occurs
*/
public void run( final Object systemObject,
final WriteSystemTask task
) throws ModelspaceException {
try {
final Session session = systemSession();
try {
task.run( session, systemNode( session, systemObject ) );
session.save();
LOGGER.debug( "Session saved" );
} catch ( final RuntimeException | ModelspaceException e ) {
throw e;
} catch ( final Exception e ) {
throw new ModelspaceException( e, "Unable to perform write system task" );
} finally {
session.logout();
}
} catch ( final RepositoryException e ) {
throw new ModelspaceException( e, "Unable to open session for write system task" );
}
}
/**
* Runs the supplied task after logging into and starting a session with the underlying repository engine, then afterwards
* closes the session. It is the caller's responsibility to save any changes made within the session.
*
* @param task
* the task to run
* @throws ModelspaceException
* if any error occurs
*/
public void run( final Task task ) throws ModelspaceException {
try {
final Session session = session();
try {
task.run( session );
} catch ( final RuntimeException | ModelspaceException e ) {
throw e;
} catch ( final Exception e ) {
throw new ModelspaceException( e, "Unable to perform task" );
} finally {
session.logout();
}
} catch ( final RepositoryException e ) {
throw new ModelspaceException( e, "Unable to open session for task" );
}
}
/**
* Runs the supplied task after logging into and starting a session with the underlying repository engine, then afterwards
* closes the session. It is the caller's responsibility to save any changes made within the session.
*
* @param task
* the task to run
* @return the return value of the supplied task
* @throws ModelspaceException
* if any error occurs
*/
public < T > T run( final TaskWithResult< T > task ) throws ModelspaceException {
try {
final Session session = session();
try {
return task.run( session );
} catch ( final RuntimeException | ModelspaceException e ) {
throw e;
} catch ( final Exception e ) {
throw new ModelspaceException( e, "Unable to perform task with result" );
} finally {
session.logout();
}
} catch ( final RepositoryException e ) {
throw new ModelspaceException( e, "Unable to open session for task with result" );
}
}
/**
* Runs the supplied task after logging into and starting a session with the underlying repository engine, then afterwards saves
* and closes the session.
*
* @param task
* the write task to run
* @throws ModelspaceException
* if any error occurs
*/
void run( final WriteTask task ) throws ModelspaceException {
try {
final Session session = session();
try {
task.run( session );
session.save();
LOGGER.debug( "Session saved" );
} catch ( final RuntimeException | ModelspaceException e ) {
throw e;
} catch ( final Exception e ) {
throw new ModelspaceException( e, "Unable to perform write task" );
} finally {
session.logout();
}
} catch ( final RepositoryException e ) {
throw new ModelspaceException( e, "Unable to open session for write task" );
}
}
/**
* Runs the supplied task after logging into and starting a session with the underlying repository engine, then afterwards saves
* and closes the session.
*
* @param task
* the write task to run
* @return the return value of the supplied task
* @throws ModelspaceException
* if any error occurs
*/
< T > T run( final WriteTaskWithResult< T > task ) throws ModelspaceException {
try {
final Session session = session();
try {
final T returnValue = task.run( session );
session.save();
LOGGER.debug( "Session saved" );
return returnValue;
} catch ( final RuntimeException | ModelspaceException e ) {
throw e;
} catch ( final Exception e ) {
throw new ModelspaceException( e, "Unable to perform write task with result" );
} finally {
session.logout();
}
} catch ( final RepositoryException e ) {
throw new ModelspaceException( e, "Unable to open session for write task with result" );
}
}
private void saveExternalLocation( final String path,
final String location ) throws ModelspaceException {
run( new WriteTask() {
@Override
public void run( final Session session ) throws Exception {
session.getNode( path ).setProperty( ModelspaceLexicon.Model.EXTERNAL_LOCATION, location );
}
} );
}
private Session session() throws ModelspaceException, RepositoryException {
return repository().login( "default" );
}
private Node systemNode( final Session session,
final Object systemObject ) throws RepositoryException {
final String path = '/' + systemObject.getClass().getSimpleName();
if ( session.nodeExists( path ) ) return session.getNode( path );
return session.getRootNode().addNode( path );
}
private Session systemSession() throws ModelspaceException, RepositoryException {
return repository().login( Modelspace.class.getSimpleName() );
}
}